package gameStates.gui;

import networking.messages.syncMessages.ValueType;

import org.fenggui.util.Color;

import com.jme.scene.Node;

import settings.Config;

import fileHandling.language.interfaces.HUDText;
import fileHandling.language.LanguageLoader;
import gameStates.absGamesStates.AbsIngameState;
import gameStates.absGamesStates.gui.AbsHUDState;
import gameStates.passes.AbsPassManagerState;
import interfaces.hud.BasicHUD;
import interfaces.hud.chat.ChatType;
import interfaces.hud.pilot.PilotHUD;
import interfaces.hud.spectate.SpectateHUD;
import interfaces.hud.targetInfos.NodeTargetArrow;
import interfaces.hud.targetInfos.TargetAngles;
import interfaces.hud.targetInfos.AbsTargetArrow;
import logic.common.missions.Mission;
import logic.common.player.Player;
import logic.common.player.playerListeners.HunterChangedEvent;
import logic.common.player.playerListeners.KillAssistEvent;
import logic.common.player.playerListeners.KillEvent;
import logic.common.player.playerListeners.MissionAssistEvent;
import logic.common.player.playerListeners.PlayerListener;
import logic.common.player.playerListeners.PlayerValueListener;
import logic.common.player.playerListeners.RespawnEvent;
import logic.common.player.playerListeners.TargetChangedEvent;
import logic.common.team.Team;
import logic.common.team.teamListeners.MissionAddedEvent;
import logic.common.team.teamListeners.MissionCompletedEvent;
import logic.common.team.teamListeners.MissionDeletedEvent;
import logic.common.team.teamListeners.TeamMissionListener;
import logic.nodes.TeamNode;
import logic.ships.hunter.HeatSeekerListener;
import logic.ships.hunter.HeatseekerFiredEvent;
import logic.ships.hunter.Hunter;
import logic.status.StatusChangedEvent;
import main.listeners.listenerClasses.gui.ChatActivatedEvent;
import main.listeners.listenerClasses.gui.ConsoleToggleEvent;
import main.listeners.listenerClasses.gui.GUIListener;
import main.listeners.listenerClasses.gui.IngameChangedEvent;
import main.listeners.listenerClasses.gui.ScoreBoardToggleEvent;
import main.listeners.listenerClasses.gui.SpawnMenuChangedEvent;

/**
 * Displays a Heads-Up-Display that shows useful information for {@link Player}s.
 * 
 * @author Wasserleiche
 */
public class HUDState extends AbsHUDState {
	
	private Node targetNode;
	private TeamNode currentMarkedTarget;
		
	private HeatSeekerListener hsListener;
	
	public static final Color[] KILL_INFO_COLORS = new Color[] { Color.WHITE, Color.LIGHT_RED };
	
	/**
	 * Creates a new HUDState and initializes the {@link BasicHUD} with the given type.
	 * @param type The type of the HUD.
	 */
	public HUDState(AbsIngameState ingameState, AbsPassManagerState passManagerState) {
		super(ingameState, passManagerState, true);
		
		targetNode = new Node("HUD Target Node");
		
		hsListener = new HeatSeekerListener() {
			@Override
			public void heatSeekerFired(HeatseekerFiredEvent event) {
				pilotHUD.enableHeatSeekerWarning(event.fired());
			}
		};
		
		addListenerToClearer(new GUIListener() {
			@Override
			public void ingameChanged(IngameChangedEvent event) {
				setActive(event.isIngame() && !event.spawnMenuWasActive());
			}
			
			@Override
			public void consoleToggled(ConsoleToggleEvent event) {
				enableInput(!event.getValue());
			}
			
			@Override
			public void spawnMenuChanged(SpawnMenuChangedEvent event) {
				setActive(!active);
			}
			
			@Override
			public void scoreBoardToggled(ScoreBoardToggleEvent event) {
				setActive(!event.scoreBoardIsActive() && !event.spawnMenuWasActive());
			}
			
			@Override
			public void chatActivated(ChatActivatedEvent event) {}
		});
		
		final Player player = ingameState.getPlayer();
		addListener(player, new PlayerListener() {
			@Override
			public void respawned(RespawnEvent event) {
				setHUD(pilotHUD);
				addListener(player.getHunter(), hsListener);
				
				if(player.getCurrentTarget() != null) player.getCurrentTarget().setMarked(true);
				else if(currentMarkedTarget != null) currentMarkedTarget.setMarked(false);
			}
			
			@Override
			public void targetChanged(TargetChangedEvent event) {
				changeMarkedTarget(event.getNewTarget());
			}
			
			@Override
			public void killed(KillEvent event) {
				Player victim = event.getVictim();
				
				Color[] colors = KILL_INFO_COLORS;
				String[] text = getKillInfoText(victim);
			
				pilotHUD.addToInfoContent(text, colors, victim.getHunter().getDestroyMoney());
			}
			
			@Override
			public void killAssist(KillAssistEvent event) {
				Player victim = event.getVictim();
				
				String youKilled = LanguageLoader.get(HUDText.Kill_Assist);
				String[] text = new String[] { youKilled, victim.getName() };
				Color[] colors = new Color[] { Color.WHITE, Color.LIGHT_RED };
				
				pilotHUD.addToInfoContent(text, colors, Player.KILL_ASSIST_MONEY);
			}
			
			@Override
			public void missionAssist(MissionAssistEvent event) {
				Mission mission = event.getMission();
				
				String[] text = mission.getAssistTexts();
				Color[] colors = mission.getAssistColors();
				
				pilotHUD.addToInfoContent(text, colors, mission.getAssistMoney());
			}
			
			@Override
			public void hunterChanged(HunterChangedEvent event) {}
		});
		
		addListener(player, new PlayerValueListener() {
			@Override
			public void valueChanged(StatusChangedEvent event) {
				ValueType type = event.getType();
				if(type == ValueType.Deaths) {
					pilotHUD.enableHeatSeekerWarning(false);
					player.getHunter().removeHeatSeekerListener(hsListener);
				} else if(type == ValueType.Money) updateMoney(event.getIntValue());
			}
		});
		
		addListener(player.getTeam(), new TeamMissionListener() {
			@Override
			public void missionCompleted(MissionCompletedEvent event) {
				Player p = event.getPlayer();
				if(p == player) {
					Mission mission = event.getMission();
					String[] texts = mission.getInfoTexts();
					Color[] colors = mission.getInfoColors();
					int money = mission.getRewardMoney();
					pilotHUD.addToInfoContent(texts, colors, money);
				}
			}
			
			@Override
			public void missionAdded(MissionAddedEvent event) {}
			@Override
			public void missionDeleted(MissionDeletedEvent event) {}
		});
		
		addKillListeners(ingameState.getGame().getTeamA());
		addKillListeners(ingameState.getGame().getTeamB());
	}
	
	private void addKillListeners(Team team) {
		for(Player player : team.getAllPlayers()) {
			addListener(player, getKillListener(player));
		}
	}
	
	@Override
	public PlayerListener getKillListener(final Player player) {
		return new PlayerListener() {
			@Override
			public void killed(KillEvent event) {
				pilotHUD.addToKillContent(player, event.getVictim(), event.getWeapon());
			}
			
			@Override
			public void respawned(RespawnEvent event) {}
			@Override
			public void hunterChanged(HunterChangedEvent event) {}
			@Override
			public void targetChanged(TargetChangedEvent event) {}
			@Override
			public void killAssist(KillAssistEvent event) {}
			@Override
			public void missionAssist(MissionAssistEvent event) {}
		};
	}
	
	@Override
	protected void setHUD(BasicHUD hud) {
		currentHUD = hud;
		interfaceElement = currentHUD;
		
		guiDisp.removeAllWidgets();
		
		rootNode = currentHUD.getRootNode();
		rootNode.attachChild(targetNode);
		
		updateWidgets = currentHUD.getUpdateWidgets();
		guiDisp.addWidget(currentHUD.getBasicContent());
	}
	
	@Override
	public void render(float tpf) {
		if(Config.get().getShowHUD()) super.render(tpf);
	}
	
	/**
	 * Restores this HUDState. The current {@link BasicHUD} will be cleaned and a new one will be 
	 * created according to the current type.
	 */
	@Override
	public void restore() {
		super.restore();
		getCurrentHUD().clean();
		initHUDs();
		if(currentHUD instanceof PilotHUD) setHUD(pilotHUD);
		else if(currentHUD instanceof SpectateHUD) setHUD(spectateHUD);
		else setHUD(basicHUD);
	}
	
	@Override
	public void registerTeamNode(TeamNode node) {		
		TargetAngles angles = new TargetAngles(node, this);
		node.setAngles(angles);
		targetNode.attachChild(angles);
		
		if(node instanceof Hunter) {
			Hunter hunter = (Hunter)node;
			AbsTargetArrow arrow = new NodeTargetArrow(hunter, this);
			hunter.setArrow(arrow);
			targetNode.attachChild(arrow);
		}
	}
	
	@Override
	public void unRegisterTeamNode(TeamNode node) {
		targetNode.detachChild(node.getAngles());
				
		if(node instanceof Hunter) {
			Hunter hunter = (Hunter)node;
			targetNode.detachChild(hunter.getArrow());
		}
	}
	
	@Override
	public void showChatText(String text, ChatType type) {
		getCurrentHUD().showChatText(text, type);
	}
	
	public static String[] getKillInfoText(Player victim) {
		String youKilled = LanguageLoader.get(HUDText.You_Killed);
		return new String[] { youKilled, victim.getName() };
	}
	
	@Override
	public void setSpectatedHUD() { setHUD(spectateHUD); }
	
	@Override
	public void nextPlayer(boolean next) {
		assert(currentHUD == spectateHUD);
		spectateHUD.changeSpectatedPlayer(next);
	}
	
	@Override
	public void changeMarkedTarget(Hunter newTarget) {
		if(currentMarkedTarget != null) currentMarkedTarget.setMarked(false);
		
		currentMarkedTarget = newTarget;
		currentMarkedTarget.setMarked(true);
		
		pilotHUD.enableAimPointer(true);
		pilotHUD.setAimPointerTarget(newTarget);
	}
}